/* 
 *  Copyright 2012 CodeMagi, Inc.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  This product includes software developed by the
 *  Apache Software Foundation (http://www.apache.org/).
 *  The Apache Software Foundation in no way endorses or
 *  promotes this product.
 */
package com.codemagi.taglibs.input;

import com.codemagi.util.OrderedTable;
import com.codemagi.util.Utils;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.*;
import org.apache.log4j.*;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * This class implements the &lt;input:select&gt; tag, which presents a
 * &lt;select&gt; form element. If multiple elements need to be selected, 
 * use MultiSelect instead. 
 *
 * @version 1.0
 * @author Shawn Bayern for Apache Software Foundation (Original Author)
 * @author August Detlefsen for CodeMagi, Inc.
 */
public class Select extends Input {

    //Logger to view debug output
    Logger log = Logger.getLogger(this.getClass());

    private OrderedTable options;	// what are our options? :)
    private OrderedTable optionIcons;   // icons for the individual options

    public void setOptions(OrderedTable x) {
	options = x;
    }

    public void setOptions(String x) {
	options        = new OrderedTable();

	try {
	    JSONArray json = new JSONArray(x);
	    
	    for (int i = 0; i < json.length(); i++) {
		JSONObject option = json.getJSONObject(i);
		
		options.put(option.get("id"), option.get("name"));
	    }
	} catch (JSONException jse) {
	    //nada
	}
    }

    public void setOptionIcons(OrderedTable newValue) {
	optionIcons = newValue;
    }
    
    public int doStartTag() throws JspException {

	log.debug("Select.doStartTag(): dVal = " + dVal);

	try {
	    // sanity check
	    if (name == null || name.equals(""))
		throw new JspTagException("invalid null or empty 'name'");
	    
	    // get what we need from the page
	    ServletRequest req = pageContext.getRequest();
	    JspWriter out = pageContext.getOut();
	    
	    // start building up the tag
	    out.println();
	    out.println("<select ");
	    out.println("    name=\"" + Util.quote(name) + "\"");
	    if (!Utils.isEmpty(id)) {
		out.println("    id=\"" + Util.quote(id) + "\"");
	    }
	    
	    if (!Utils.isEmpty(onChange)) {
		out.println("    OnChange=\"" + Util.quote(onChange) + "\"");
	    }
	    
	    //disable the form field if disabled is set                                                     
            if (disabled) {
                out.println("    readonly=\"readonly\"");
                out.println("    OnFocus=\"blur();\"");
		appendAttribute("style", "cursor:default;");
            }

	    // include any attributes we've got here
	    Util.printAttributes(out, attributes);
	    
	    //if this is a required field and it is not filled out, do something...
	    if ( !Utils.isEmpty((String)req.getAttribute("error_" + name + "_error")) ) {
                out.println("    class=\"" + markupClass + " error\"");
            }else if ( !Utils.isEmpty(markupClass) ) {
                out.println("    class=\"" + markupClass + "\"");
            }

	    // end the starting tag
	    out.println(">");
	    
	    /*
	     * Print out our options, selecting one or more if appropriate.
	     * If there are multiple selections but the page doesn't call
	     * for a <select> that accepts them, ignore the selections.
	     * This is preferable to throwing a JspException because the
	     * (end) user can control input, and we don't want the user
	     * causing exceptions in our application.
	     */
	    
	    // get the current selection. 
	    // NOTE that this is a single select list and should 
	    // only have ONE item selected
            String selected = getParameter(name, (HttpServletRequest)req);
	    log.debug("Select: selected: " + selected);

	    if ( Utils.isEmpty(selected) || override ) {
		log.debug("Select: building chosen from default: " + dVal);                                             
		selected = dVal;
	    }

	    // actually print the <option> tags
	    if (options != null) {

		Collection c = (Collection)(options.orderedKeys());
		Iterator i   = c.iterator();
		
		while (i.hasNext()) {
		    
		    String key;
		    Object value;
		    String icon  = null;

		    try {
			key   = (String)i.next();
			if (key == null) continue;  //do not allow null keys
			value = options.get(key);

			//determine if there is an icon for this option
			if (optionIcons != null) icon = (String)optionIcons.get(key);			

		    } catch (ClassCastException cce) {
			/* If the option contains non-Strings, give the user
			 * a more meaningful message than what he or she would get
			 * if we just propagated a ClassCastException back.
			 */
			throw new JspTagException("all members in options Map must be Strings");
		    }
		    
		    if (value == null) value = key;		// use key if value is null
		    
		    out.print("<option value=\"" + Util.quote(key) + "\"");
		    
		    //determine if this option should be selected
		    if ( key.equals(selected) ) out.print(" selected=\"selected\"");
		    
		    if (!Utils.isEmpty(icon)) out.print(" style=\"background-image: url(" + icon + ");\"");

		    out.print(">");
		    if (value instanceof String) {
			out.print(Util.quote( (String)value ));
		    } else {
			out.print(Util.quote( value.toString() ));
		    }
		    out.println("</option>");
		}
	    }
	    
	    // close off the surrounding select
	    out.println("</select>");
	    
            //show the error message
            if (showError) {
                String errorMessage = (String)req.getAttribute(name + "_error_message");
                if ( !Utils.isEmpty(errorMessage) ) {
                    out.print( "<BR><SPAN CLASS=\"input_error_msg\">" + errorMessage + "</SPAN>");
                }
            }
	    
	} catch (Exception ex) {
	    log.debug("", ex);
	    throw new JspTagException(ex.getMessage());
	}
	return SKIP_BODY;
    }
}
